package com.superbytecode.cloud.redis.lock;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.concurrent.TimeUnit;

/**
 * All rights Reserved, Designed By www.super-master.com
 *
 * @ProjectName: sanskrit
 * @Package: com.superbytecode.cloud.redis.lock
 * @ClassName: RedissonLocker
 * @Description: [Redisson加锁实现]
 * <p> </p>
 * @Author: [Lance Ting]
 * @Date: 2024/8/19 11:14
 * @Version: V1.0
 * @Copyright: 2024 www.super-master.cn Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@Slf4j
@AllArgsConstructor
public class RedissonLocker implements Locker {
    private static final ThreadLocal<RLock> LOCK_THREAD_LOCAL = new ThreadLocal<>();
    private final LockType lockType;
    private final RedissonClient redissonClient;

    /**
     * 加锁
     *
     * @param key         锁key
     * @param releaseTime 自动释放时间
     * @param waitTime    加锁等待时间
     * @param unit        时间单位
     * @return 是否加锁成功
     * @throws InterruptedException InterruptedException
     */
    @Override
    public boolean lock(String key, int releaseTime, int waitTime, TimeUnit unit)//
            throws InterruptedException {
        RLock lock = getRLock(key);
        LOCK_THREAD_LOCAL.set(lock);
        log.info("加锁，thread：{}，key：{}", currentThreadId(), key);
        return lock.tryLock(waitTime, releaseTime, unit);
    }

    /**
     * 解锁
     */
    @Override
    public void unlock() {
        log.info("解锁，thread：{}，key：{}", currentThreadId(), LOCK_THREAD_LOCAL.get().getName());
        LOCK_THREAD_LOCAL.get().unlock();
        LOCK_THREAD_LOCAL.remove();
    }

    private RLock getRLock(String key) {
        switch (lockType) {
            case REDIS_FAIR_LOCK:
                return redissonClient.getFairLock(key);
            case REDIS_SPIN_LOCK:
                return redissonClient.getSpinLock(key);
            case REDIS_REENTRANT_LOCK:
                return redissonClient.getLock(key);
            default:
                throw new IllegalArgumentException("错误的锁类型");
        }
    }

    private long currentThreadId() {
        return Thread.currentThread().getId();
    }
}